﻿using System.Collections.Generic;

namespace Raven
{
    public class GoalThink : GoalComposite<RavenBot>
    {
        private List<GoalEvaluator> _goalEvaluators;

        public GoalThink(RavenBot owner) : base(owner, GoalType.goal_think)
        {
            //these biases could be loaded in from a script on a per bot basis
            //but for now we'll just give them some random values
            Fix LowRangeOfBias = Fix.Ratio(1, 2);
            Fix HighRangeOfBias = Fix.Ratio(3, 2);

            Fix HealthBias = _owner.GetWorld().GetRandom().RandInRange(LowRangeOfBias, HighRangeOfBias);
            Fix ShotgunBias = _owner.GetWorld().GetRandom().RandInRange(LowRangeOfBias, HighRangeOfBias);
            Fix RocketLauncherBias = _owner.GetWorld().GetRandom().RandInRange(LowRangeOfBias, HighRangeOfBias);
            Fix RailgunBias = _owner.GetWorld().GetRandom().RandInRange(LowRangeOfBias, HighRangeOfBias);
            Fix ExploreBias = _owner.GetWorld().GetRandom().RandInRange(LowRangeOfBias, HighRangeOfBias);
            Fix AttackBias = _owner.GetWorld().GetRandom().RandInRange(LowRangeOfBias, HighRangeOfBias);

            //create the evaluator objects
            _goalEvaluators = new List<GoalEvaluator>();
            _goalEvaluators.Add(new GetHealthGoalEvaluator(HealthBias));
            _goalEvaluators.Add(new ExploreGoalEvaluator(ExploreBias));
            _goalEvaluators.Add(new AttackTargetGoalEvaluator(AttackBias));

            _goalEvaluators.Add(new GetWeaponGoalEvaluator(RailgunBias, EntityType.RailGunWeaponGiver));
            _goalEvaluators.Add(new GetWeaponGoalEvaluator(ShotgunBias, EntityType.ShotgunWeaponGiver));
            _goalEvaluators.Add(new GetWeaponGoalEvaluator(RocketLauncherBias, EntityType.RocketLauncherWeaponGiver));
        }

        public override void Activate()
        {
            if (!_owner.isPossessed())
            {
                Arbitrate();
            }

            _status = GoalStatus.active;
        }

        public override GoalStatus Process()
        {
            ActivateIfInactive();

            GoalStatus SubgoalStatus = ProcessSubgoals();

            if (SubgoalStatus == GoalStatus.completed || SubgoalStatus == GoalStatus.failed)
            {
                if (!_owner.isPossessed())
                {
                    _status = GoalStatus.inactive;
                }
            }

            return _status;
        }

        public override void Terminate()
        {
        }

        public void AddGoalExplore()
        {
            if (notPresent(GoalType.goal_explore))
            {
                RemoveAllSubgoals();
                AddSubgoal(new GoalExplore(_owner));
            }
        }

        public void AddGoalWander()
        {
            if (notPresent(GoalType.goal_wander))
            {
                RemoveAllSubgoals();
                AddSubgoal(new GoalWander(_owner));
            }
        }

        public void AddGoalGetItem(EntityType ItemType)
        {
            if (notPresent(GoalGetItem.ItemTypeToGoalType(ItemType)))
            {
                RemoveAllSubgoals();
                AddSubgoal(new GoalGetItem(_owner, ItemType));
            }
        }

        public void AddGoalAttackTarget()
        {
            if (notPresent(GoalType.goal_attack_target))
            {
                RemoveAllSubgoals();
                AddSubgoal(new GoalAttackTarget(_owner));
            }
        }

        //---------------------------- notPresent --------------------------------------
        //
        //  returns true if the goal type passed as a parameter is the same as this
        //  goal or any of its subgoals
        //-----------------------------------------------------------------------------
        public bool notPresent(GoalType GoalType)
        {
            if (_subGoalList.Count > 0)
            {
                return _subGoalList.First.Value.GetGoalType() != GoalType;
            }

            return true;
        }

        //----------------------------- Update ----------------------------------------
        // 
        //  this method iterates through each goal option to determine which one has
        //  the highest desirability.
        //-----------------------------------------------------------------------------
        public void Arbitrate()
        {
            Fix best = 0;
            GoalEvaluator MostDesirable = null;

            //iterate through all the evaluators to see which produces the highest score
            foreach (var curDes in _goalEvaluators)
            {
                Fix desirabilty = curDes.CalculateDesirability(_owner);

                if (desirabilty >= best)
                {
                    best = desirabilty;
                    MostDesirable = curDes;
                }
            }

            Utility.Assert(MostDesirable != null, "<Goal_Think::Arbitrate>: no evaluator selected");

            MostDesirable.SetGoal(_owner);
        }
    }
}